#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/intersect.hpp>

namespace raycast {
	class quad {
	private:
		glm::vec3 _center; // xz 平面中心坐标
		float _width; // 以 x 轴为度量
		float _height; // 以 z 轴为度量
		
		glm::vec3 _vertices[4]; // 采用 triangle strip 绘制
		GLuint _vao, _bo;
		
	private:
		void
		generate_vertices() {
			glm::vec3 lefttop = _center + glm::vec3(-_width / 2.0f, 0.0f, -_height / 2.0f);
			glm::vec3 leftbottom = _center + glm::vec3(-_width / 2.0f, 0.0f, _height / 2.0f);
			glm::vec3 righttop = _center + glm::vec3(_width / 2.0f, 0.0f, -_height / 2.0f);
			glm::vec3 rightbottom = _center + glm::vec3(_width / 2.0f, 0.0f, _height / 2.0f);

			_vertices[0] = lefttop;
			_vertices[1] = leftbottom;
			_vertices[2] = righttop;
			_vertices[3] = rightbottom;
		}

		void
		updatedata() {
			glBindBuffer(GL_ARRAY_BUFFER, _bo);
			glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_vertices), _vertices);
			glBindBuffer(GL_ARRAY_BUFFER, 0);
		}

	public:
		quad(const glm::vec3 &center, float width, float height) 
			: _center(center)
			, _width(width)
			, _height(height) {
				
		}

		~quad() {
			if (_vao != 0)
				glDeleteVertexArrays(1, &_vao);
			if (_bo != 0)
				glDeleteBuffers(1, &_bo);
		}

		void
		init() {
			generate_vertices();

			glGenBuffers(1, &_bo);
			glBindBuffer(GL_ARRAY_BUFFER, _bo);
			glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_DYNAMIC_DRAW);
			glBindBuffer(GL_ARRAY_BUFFER, 0);

			glGenVertexArrays(1, &_vao);
			glBindVertexArray(_vao);
				glBindBuffer(GL_ARRAY_BUFFER, _bo);
				glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
				glEnableVertexAttribArray(0);
			glBindVertexArray(0);
		}

		float
		getheight() {
			return _height;
		}

		void
		move(const glm::vec3 &center) {
			_center = center;
			generate_vertices();
			updatedata();

		}

		void 
		draw() {
			glBindVertexArray(_vao);
				glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
			glBindVertexArray(0);
		}

		bool
		isintersect(const glm::vec3 &raypos, const glm::vec3 &raydir) {
			glm::vec3 barypos;
			if (glm::intersectRayTriangle(raypos, raydir, _vertices[0], _vertices[1], _vertices[2], barypos))
				return true;
			if (glm::intersectRayTriangle(raypos, raydir, _vertices[1], _vertices[3], _vertices[2], barypos))
				return true;
			return false;
		}

		bool
		intersect(const glm::vec3 &raypos, const glm::vec3 &raydir, glm::vec3 &barypos) {
			float dist;
			glm::vec3 v1(_vertices[2] - _vertices[1]);
			glm::vec3 v2(_vertices[0] - _vertices[1]);
			glm::vec3 normal = glm::normalize(glm::cross(v1, v2));
			if (glm::intersectRayPlane(raypos, raydir, _center, normal, dist)) {
				barypos =  raypos + raydir * dist;
				return true;
			} else {
				return false;
			}
		}
	};
}
